/*	--- 使用JSON --- 

JSON, JavaScript Object Notation 
Notation  n.  表示法;符号说明;符号


前面我们讨论了XML这种数据格式。

【XML的特点】是【功能全面, 但标签繁琐, 格式复杂】。

在Web上使用XML现在越来越少, 取而代之的是【JSON】这种数据结构。

JSON是JavaScript Object Notation的缩写, 它去除了所有【JavaScript执行代码】, 只保留【JavaScript的对象格式】。

一个典型的JSON如下：

	{
	    "id": 1,
	    "name": "Java核心技术",
	    "author": {
	        "firstName": "Abc",
	        "lastName": "Xyz"
	    },
	    "isbn": "1234567",
	    "tags": ["Java", "Network"]
	}



【JSON】作为【数据传输的格式】, 有几个显著的优点：
	· JSON只允许使用【UTF-8编码】, 不存在编码问题; 
	· JSON只允许使用【双引号】作为【key】, 特殊字符用\转义, 格式简单; 
	· 【浏览器】内置【JSON支持】, 如果把数据用JSON发送给浏览器, 可以用JavaScript直接处理。


因此, JSON适合表示【层次结构】, 因为它格式简单, 仅支持以下几种数据类型：
	· 键值对：{"key": value}
	· 数组：[1, 2, 3]
	· 字符串："abc"
	· 数值（整数和浮点数）：12.34
	· 布尔值：true或false
	· 空值：null


【浏览器】直接支持使用【JavaScript】对【JSON】进行【读写】：*/

// JSON string to JavaScript object:
jsObj = JSON.parse(jsonStr);

// JavaScript object to JSON string
jsonStr = JSON.stringify(jsObj);



/*
所以, 开发Web应用的时候, 使用【JSON】作为【数据传输】, 在【浏览器端】非常方便。

因为【JSON】天生适合【JavaScript】处理, 所以, 绝大多数【REST API】都选择【JSON】作为【数据传输格式】。

----------------------


现在问题来了：使用Java如何对JSON进行读写？

在Java中, 针对JSON也有标准的JSR 353 API, 但是我们在前面讲XML的时候发现, 如果能直接在【XML】和【JavaBean】之间互相转换是最好的。

类似的, 如果能直接在【JSON】和【JavaBean】之间转换, 那么用起来就简单多了。

常用的用于【解析JSON】的第三方库有：
	· Jackson
	· Gson
	· Fastjson
	· ...


注意到上一节提到的那个可以【解析XML】的浓眉大眼的【Jackson】也可以【解析JSON】！

因此我们只需要引入【以下Maven依赖】：
	· com.fasterxml.jackson.core:jackson-databind:2.10.0
	


就可以使用下面的代码解析【一个JSON文件】：*/
InputStream input = Main.class.getResourceAsStream("/book.json");

ObjectMapper mapper = new ObjectMapper();
// Deserialization反序列化时, 忽略不存在的JavaBean属性
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
Book book = mapper.readValue(input, Book.class);
	// JSON -> InputStream -> ObjectMapper.readValue(JSON, Output.class)


/*
核心代码是创建一个【ObjectMapper对象】。

关闭DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES功能使得解析时如果【JavaBean】不存在该【属性】时, 解析不会报错。

把JSON解析为JavaBean的过程称为反序列化。如果把JavaBean变为JSON, 那就是序列化。要实现JavaBean到JSON的序列化, 只需要一行代码：*/
String json = mapper.writeValueAsString(book);


/*
要把JSON的某些值解析为特定的Java对象, 例如LocalDate, 也是完全可以的。例如：

	{
	    "name": "Java核心技术",
	    "pubDate": "2016-09-01"
	}


要解析为：*/
public class Book {
    public String name;
    public LocalDate pubDate;
}



/*
只需要引入【标准的JSR 310】关于【JavaTime的数据格式】定义至【Maven】：
  com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.10.0


然后, 在【创建ObjectMapper】时, 注册一个【新的JavaTimeModule】：*/
ObjectMapper mapper = new ObjectMapper().registerModule(new JavaTimeModule());


/*
有些时候, 【内置的解析规则】和【扩展的解析规则】如果都不满足我们的需求, 还可以【自定义解析】。

举个例子, 假设Book类的isbn是一个BigInteger：*/
public class Book {
	public String name;
	public BigInteger isbn;
}


/*
但JSON数据并不是标准的整形格式：

	{
	    "name": "Java核心技术",
	    "isbn": "978-7-111-54742-6"
	}


直接解析, 肯定报错。

这时, 我们需要自定义一个IsbnDeserializer, 用于解析含有非数字的字符串：*/
public class IsbnDeserializer extends JsonDeserializer<BigInteger> {
	public BigInteger deserialize(JsnoParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
		// 读取原始的JSON字符串内容
		String s = p.getValueAsString();

		if (s != null) {
			try {
				return new BigInteger(s.replace("-", ""));
			} catch (NumberFormatException e) {
				throw new JsonParserException(p, s, e);
			}
		}

		return null;
	}
}



// 然后, 在Book类中使用【注解】标注：
public class Book {
	public String name;

	// 表示 反序列化isbn时, 使用自定义的IsbnDeserializer
	@JsonDeserializer(using = IsbnDeserializer.class) // <--注解
	public BigInteger isbn;
}


// 类似的, 自定义序列化时我们需要自定义一个IsbnSerializer, 然后在Book类中标注@JsonSerialize(using = ...)即可。




/*========================================================


#	----- 使用JSON の 小结 -----

1. JSON是轻量级的数据表示方式, 常用于Web应用; 

2. Jackson可以实现JavaBean和JSON之间的转换; 

3. 可以通过Module扩展Jackson能处理的数据类型; 

4. 可以自定义JsonSerializer和JsonDeserializer来定制序列化和反序列化。







*/






































